package com.xu.cloud.common.template;

import com.xu.cloud.common.pojo.http.req.BaseRequest;
import com.xu.cloud.common.pojo.http.resp.BaseResponse;
import com.xu.cloud.common.process.IProcessor;
import com.xu.cloud.common.tx.ITransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 模板方法抽象类
 *
 * @author xuguan
 * @since 2023/4/3
 */
public abstract class AbstractRequestTxTemplate<Req extends BaseRequest, Resp extends BaseResponse>
        implements RequestTemplate<Req, Resp>, IProcessor<Req, Resp> {
    protected static final Logger log = LoggerFactory.getLogger(AbstractRequestTxTemplate.class);

    @Autowired
    protected ITransaction tx;

    /**
     * 带事务的请求执行前业务
     * 注意: preRequest方法无异常就会提交事务
     */
    protected void preRequestTx(Req req) {
        tx.startTransaction();
        log.info(">>>>>>>>>>> transaction created finish, transaction start");

        try {
            log.info(">>>>>>>>>>> preRequest start");
            this.preRequest(req);
            log.info(">>>>>>>>>>> preRequest end");

            tx.commit();
            log.info(">>>>>>>>>>> transaction commit");
        } catch (Exception e) {
            log.error(">>>>>>>>>>> preRequest fail");

            tx.rollback();
            log.error(">>>>>>>>>>> transaction rollback");
            throw e;
        }
    }


    /**
     * 带事务的请求执行业务
     */
    public Resp requestTx(Req req) {
        try {
            tx.startTransaction();
            log.info(">>>>>>>>>>> transaction created finish, transaction start");

            log.info(">>>>>>>>>>> request start");
            Resp resp = this.request(req);
            log.info(">>>>>>>>>>> request end");

            tx.commit();
            log.info(">>>>>>>>>>> transaction commit");

            return resp;
        } catch (Exception e) {
            log.error(">>>>>>>>>>> request fail");

            tx.rollback();
            log.error(">>>>>>>>>>> transaction rollback");

            throw e;
        }
    }

    @Override
    public Resp process(Req req) {
        Resp resp = null;
        Exception ex = null;
        try {
            this.recv(req);
            this.valid(req);
            this.check(req);
            this.preRequestTx(req);
            resp = this.requestTx(req);
            return resp;
        } catch (Exception e) {
            log.error(">>>>>>>>>>> request fail");
            ex = e;
            throw e;
        } finally {
            try {
                this.postRequest(req, resp, ex);
            } catch (Exception e) {
                log.error(">>>>>>>>>>> postRequest fail, not throw exception");
            }
        }
    }
}
